Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / rns_startup_recovery.py

Displaying Raw • Download


meshchatx/src/backend/rns_startup_recovery.py master (b89dc9e6) Text, 11.60 KB

T8b949e# SPDX-License-Identifier: 0BSD

T8b949e"""Contain RNS process-killing exits and recover from bad interface configs.

Reticulum's RNS.panic() calls os._exit(255), which kills the whole
MeshChatX process (fatal on Android where Python runs in-process). Interface
init failures can also leave the app unable to start until the user wipes
storage. This module:

1. Replaces RNS.panic / RNS.exit with catchable exceptions
2. Forces panic_on_interface_error = No in the Reticulum config
3. Progressively disables risky interfaces and retries RNS construction
"""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations

Tff7b72import T7ee787logging
Tff7b72import T7ee787os
Tff7b72import T7ee787re
Tff7b72import T7ee787contextlib
Tff7b72from T7ee787collectionsT7ee787.T7ee787abc Tff7b72import Te6edf3Callable
Tff7b72from T7ee787typing Tff7b72import Te6edf3Any

Te6edf3logger Tff7b72= Te6edf3loggingTff7b72.Td2a8ffgetLoggerTb4b4b4(Tff7b72__name__Tb4b4b4)

Te6edf3_TRUE_STRINGS Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6fftrueTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffyesTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff1Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffonTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffyTa5d6ff"Tb4b4b4)
Te6edf3_PANIC_PATCHED Tff7b72= Tff7b72False
Te6edf3_ORIGINAL_PANIC Tff7b72= Tff7b72None
Te6edf3_ORIGINAL_EXIT Tff7b72= Tff7b72None
Te6edf3_EXIT_IN_PROGRESS Tff7b72= Tff7b72False

T8b949e# Prefer disabling these types first when init fails without a named culprit.
Te6edf3_HIGH_RISK_TYPES Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffI2PInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffRNodeMultiInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffRNodeInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffRNodeIPInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffAutoInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffSerialInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffKISSInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffAX25KISSInterfaceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffPipeInterfaceTa5d6ff"Tb4b4b4,
Tb4b4b4)


Tff7b72class T56d364RnsPanicErrorTb4b4b4(Tf85149RuntimeErrorTb4b4b4)Tb4b4b4:
T8b949e"""Raised instead of os._exit when RNS would panic or hard-exit."""


Tff7b72def Td2a8ffinstall_rns_panic_containmentTb4b4b4(Tff7b72*Tb4b4b4, Te6edf3forceTb4b4b4: Tffa657bool Tff7b72= Tff7b72FalseTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Replace RNS panic/exit with exceptions so the HTTP process can survive.

Safe to call multiple times. Returns True when the patch was applied (or
was already applied).
"""
Tff7b72global Te6edf3_PANIC_PATCHEDTb4b4b4, Te6edf3_ORIGINAL_PANICTb4b4b4, Te6edf3_ORIGINAL_EXITTb4b4b4, Te6edf3_EXIT_IN_PROGRESS
Tff7b72if Te6edf3_PANIC_PATCHED Tff7b72and Tff7b72not Te6edf3forceTb4b4b4:
Tff7b72return Tff7b72True
Tff7b72tryTb4b4b4:
Tff7b72import T7ee787RNS
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffCould not import RNS for panic containment: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tff7b72False

Tff7b72if Te6edf3forceTb4b4b4:
Te6edf3_EXIT_IN_PROGRESS Tff7b72= Tff7b72False

Tff7b72if Te6edf3_ORIGINAL_PANIC Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3_ORIGINAL_PANIC Tff7b72= Tffa657getattrTb4b4b4(Te6edf3RNSTb4b4b4, Ta5d6ff"Ta5d6ffpanicTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72if Te6edf3_ORIGINAL_EXIT Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3_ORIGINAL_EXIT Tff7b72= Tffa657getattrTb4b4b4(Te6edf3RNSTb4b4b4, Ta5d6ff"Ta5d6ffexitTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)

Tff7b72def Td2a8ff_contained_panicTb4b4b4(Tff7b72*Te6edf3_argsTb4b4b4, Tff7b72*Tff7b72*Te6edf3_kwargsTb4b4b4)Tb4b4b4:
Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffRNS.panic() was calledTa5d6ff"
Tff7b72if Te6edf3_argsTb4b4b4:
Te6edf3message Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ffRNS.panic(): Tffd700{Te6edf3_argsTb4b4b4[T79c0ff0Tb4b4b4]Tffd700}Ta5d6ff"
T8b949e# Avoid logging handlers here. Panic can run under signal context.
Tff7b72raise Te6edf3RnsPanicErrorTb4b4b4(Te6edf3messageTb4b4b4)

Tff7b72def Td2a8ff_contained_exitTb4b4b4(Te6edf3codeTb4b4b4: Tffa657int Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4:
Tff7b72global Te6edf3_EXIT_IN_PROGRESS
T8b949e# SIGINT/SIGTERM can reenter while logging or SQLite is in flight.
T8b949e# A second RNS.exit must be a no-op or FileHandlers blow up with
T8b949e# "reentrant call inside BufferedWriter".
Tff7b72if Te6edf3_EXIT_IN_PROGRESSTb4b4b4:
Tff7b72return
Te6edf3_EXIT_IN_PROGRESS Tff7b72= Tff7b72True
Tff7b72tryTb4b4b4:
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3RNSTb4b4b4, Ta5d6ff"Ta5d6ffReticulumTa5d6ff"Tb4b4b4) Tff7b72and Tffa657hasattrTb4b4b4(Te6edf3RNSTff7b72.Td2a8ffReticulumTb4b4b4, Ta5d6ff"Ta5d6ffexit_handlerTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8ffReticulumTff7b72.Td2a8ffexit_handlerTb4b4b4(Tb4b4b4)
Tff7b72finallyTb4b4b4:
Tff7b72if Te6edf3code Tff7b72!= T79c0ff0Tb4b4b4:
Te6edf3_EXIT_IN_PROGRESS Tff7b72= Tff7b72False
Tff7b72raise Te6edf3RnsPanicErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffRNS.exit(Tffd700{Te6edf3codeTffd700}Ta5d6ff) was calledTa5d6ff"Tb4b4b4)

Te6edf3RNSTff7b72.Td2a8ffpanic Tff7b72= Te6edf3_contained_panic
Te6edf3RNSTff7b72.Td2a8ffexit Tff7b72= Te6edf3_contained_exit
Te6edf3_PANIC_PATCHED Tff7b72= Tff7b72True
Te6edf3loggerTff7b72.Td2a8ffinfoTb4b4b4(Ta5d6ff"Ta5d6ffInstalled RNS panic/exit containment (os._exit disabled for RNS)Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72True


Tff7b72def Td2a8ffensure_panic_on_interface_error_disabledTb4b4b4(Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""Force panic_on_interface_error = No so interface faults cannot kill RNS."""
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72False

Te6edf3reticulum Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3reticulumTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Te6edf3reticulum Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3cfgTb4b4b4[Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3reticulum

Te6edf3current Tff7b72= Tffa657strTb4b4b4(Te6edf3reticulumTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpanic_on_interface_errorTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffNoTa5d6ff"Tb4b4b4)Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3current Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffnoTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fffalseTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff0Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffoffTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Ta5d6ff"Ta5d6ffpanic_on_interface_errorTa5d6ff" Tff7b72not Tff7b72in Te6edf3reticulumTb4b4b4:
Te6edf3reticulumTb4b4b4[Ta5d6ff"Ta5d6ffpanic_on_interface_errorTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ffNoTa5d6ff"
Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False

Te6edf3reticulumTb4b4b4[Ta5d6ff"Ta5d6ffpanic_on_interface_errorTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ffNoTa5d6ff"
Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff"Ta5d6ffFailed to disable panic_on_interface_error in Tffd700%sTa5d6ff: Tffd700%sTa5d6ff"Tb4b4b4,
Te6edf3config_pathTb4b4b4,
Te6edf3excTb4b4b4,
Tb4b4b4)
Tff7b72return Tff7b72False
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff"Ta5d6ffDisabled panic_on_interface_error in Tffd700%sTa5d6ff so interface errors cannot Ta5d6ff"
Ta5d6ff"Ta5d6ffkill the MeshChatX processTa5d6ff"Tb4b4b4,
Te6edf3config_pathTb4b4b4,
Tb4b4b4)
Tff7b72return Tff7b72True


Tff7b72def Td2a8ff_is_enabledTb4b4b4(Te6edf3ifaceTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72for Te6edf3key Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3key Tff7b72in Te6edf3iface Tff7b72and Tffa657strTb4b4b4(Te6edf3ifaceTff7b72.Td2a8ffgetTb4b4b4(Te6edf3keyTb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72in Te6edf3_TRUE_STRINGSTb4b4b4:
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False


Tff7b72def Td2a8ff_disable_ifaceTb4b4b4(Te6edf3ifaceTb4b4b4: Tffa657dictTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffinterface_enabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"
Tff7b72if Ta5d6ff"Ta5d6ffenabledTa5d6ff" Tff7b72in Te6edf3ifaceTb4b4b4:
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffenabledTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffalseTa5d6ff"


Tff7b72def Td2a8fflist_enabled_interface_namesTb4b4b4(Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72return Tb4b4b4[
Te6edf3name
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3ifaceTb4b4b4, Tffa657dictTb4b4b4) Tff7b72and Te6edf3_is_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)
Tb4b4b4]


Tff7b72def Td2a8ffdisable_named_interfaces_in_configTb4b4b4(
Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3namesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72| Tffa657setTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
T8b949e"""Disable the named interfaces. Returns names that were actually disabled."""
Tff7b72if Tff7b72not Te6edf3names Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3disabledTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3wanted Tff7b72= Tb4b4b4{Tffa657strTb4b4b4(Te6edf3nTb4b4b4) Tff7b72for Te6edf3n Tff7b72in Te6edf3namesTb4b4b4}
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3name Tff7b72not Tff7b72in Te6edf3wanted Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3ifaceTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tff7b72not Te6edf3_is_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3_disable_ifaceTb4b4b4(Te6edf3ifaceTb4b4b4)
Te6edf3disabledTff7b72.Td2a8ffappendTb4b4b4(Te6edf3nameTb4b4b4)
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff'Ta5d6ffDisabled interface Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff during RNS startup recoveryTa5d6ff'Tb4b4b4, Te6edf3nameTb4b4b4)
Tff7b72if Tff7b72not Te6edf3disabledTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffFailed to write interface recovery config: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72return Te6edf3disabled


Tff7b72def Td2a8ffdisable_interfaces_by_typeTb4b4b4(
Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3iface_typesTb4b4b4: Tffa657tupleTb4b4b4[Tffa657strTb4b4b4, Tff7b72.Tff7b72.Tff7b72.Tb4b4b4] Tff7b72| Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3limitTb4b4b4: Tffa657int Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3cfg Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3interfaces Tff7b72= Te6edf3cfgTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3interfacesTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3type_set Tff7b72= Tb4b4b4{Tffa657strTb4b4b4(Te6edf3tTb4b4b4) Tff7b72for Te6edf3t Tff7b72in Te6edf3iface_typesTb4b4b4}
Te6edf3disabledTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3nameTb4b4b4, Te6edf3iface Tff7b72in Te6edf3interfacesTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3ifaceTb4b4b4, Tffa657dictTb4b4b4) Tff7b72or Tff7b72not Te6edf3_is_enabledTb4b4b4(Te6edf3ifaceTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tffa657strTb4b4b4(Te6edf3ifaceTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72not Tff7b72in Te6edf3type_setTb4b4b4:
Tff7b72continue
Te6edf3_disable_ifaceTb4b4b4(Te6edf3ifaceTb4b4b4)
Te6edf3disabledTff7b72.Td2a8ffappendTb4b4b4(Te6edf3nameTb4b4b4)
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(
Ta5d6ff'Ta5d6ffDisabled Tffd700%sTa5d6ff interface Ta5d6ff"Tffd700%sTa5d6ff"Ta5d6ff during RNS startup recoveryTa5d6ff'Tb4b4b4,
Te6edf3ifaceTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3nameTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3limit Tff7b72is Tff7b72not Tff7b72None Tff7b72and Tffa657lenTb4b4b4(Te6edf3disabledTb4b4b4) Tff7b72>Tff7b72= Te6edf3limitTb4b4b4:
Tff7b72break
Tff7b72if Tff7b72not Te6edf3disabledTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Te6edf3cfgTff7b72.Td2a8ffwriteTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffFailed to write typed interface recovery config: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3excTb4b4b4)
Tff7b72return Tb4b4b4[Tb4b4b4]
Tff7b72return Te6edf3disabled


Tff7b72def Td2a8ffextract_interface_names_from_errorTb4b4b4(Te6edf3errorTb4b4b4: Tf85149BaseException Tff7b72| Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
T8b949e"""Best-effort parse of interface section names from an RNS error string."""
Te6edf3text Tff7b72= Tffa657strTb4b4b4(Te6edf3errorTb4b4b4)
Te6edf3foundTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3patterns Tff7b72= Tb4b4b4(
Ta5d6ffrTa5d6ff'Ta5d6ffinterfaceTa5d6ff\Ta5d6ffs+Ta5d6ff"Ta5d6ff([^Ta5d6ff"Ta5d6ff]+)Ta5d6ff"Ta5d6ff'Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffinterfaceTa5d6ff\Ta5d6ffs+Ta5d6ff'Ta5d6ff([^Ta5d6ff'Ta5d6ff]+)Ta5d6ff'Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffI2PInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffAutoInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffTCPClientInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffTCPServerInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffRNodeInterfaceTa5d6ff\Ta5d6ff[([^Ta5d6ff\Ta5d6ff]]+)Ta5d6ff\Ta5d6ff]Ta5d6ff"Tb4b4b4,
Ta5d6ffrTa5d6ff"Ta5d6ffThe interface name Tffea00\"Ta5d6ff([^Tffea00\"Ta5d6ff]+)Tffea00\"Ta5d6ff was already usedTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72for Te6edf3pattern Tff7b72in Te6edf3patternsTb4b4b4:
Tff7b72for Te6edf3match Tff7b72in Te6edf3reTff7b72.Td2a8fffinditerTb4b4b4(Te6edf3patternTb4b4b4, Te6edf3textTb4b4b4, Te6edf3flagsTff7b72=Te6edf3reTff7b72.Td2a8ffIGNORECASETb4b4b4)Tb4b4b4:
Te6edf3name Tff7b72= Te6edf3matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3name Tff7b72and Te6edf3name Tff7b72not Tff7b72in Te6edf3foundTb4b4b4:
Te6edf3foundTff7b72.Td2a8ffappendTb4b4b4(Te6edf3nameTb4b4b4)
Tff7b72return Te6edf3found


Tff7b72def Td2a8ffapply_startup_recovery_stepTb4b4b4(
Te6edf3config_pathTb4b4b4: Tffa657strTb4b4b4,
Te6edf3errorTb4b4b4: Tf85149BaseException Tff7b72| Tffa657strTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3attemptTb4b4b4: Tffa657intTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4:
T8b949e"""Disable something that might be blocking RNS init. Returns disabled names.

Steps escalate with *attempt*:
0. Named interfaces from the error (if any), else I2P
1. RNode / serial / kiss family
2. AutoInterface
3. Any remaining enabled high-risk interface (one at a time)
"""
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backend Tff7b72import Te6edf3i2p_support
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787rnode_support Tff7b72import Tb4b4b4(
Te6edf3_is_chaquopy_androidTb4b4b4,
Te6edf3disable_rnode_interfaces_in_configTb4b4b4,
Tb4b4b4)

Te6edf3disabledTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3named Tff7b72= Te6edf3extract_interface_names_from_errorTb4b4b4(Te6edf3errorTb4b4b4)
Tff7b72if Te6edf3namedTb4b4b4:
Te6edf3disabledTff7b72.Td2a8ffextendTb4b4b4(Te6edf3disable_named_interfaces_in_configTb4b4b4(Te6edf3config_pathTb4b4b4, Te6edf3namedTb4b4b4)Tb4b4b4)
Tff7b72if Te6edf3disabledTb4b4b4:
Tff7b72return Te6edf3disabled

Tff7b72if Te6edf3attempt Tff7b72<Tff7b72= T79c0ff0Tb4b4b4:
Tff7b72if Te6edf3i2p_supportTff7b72.Td2a8ffdisable_all_i2p_in_configTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
T8b949e# Names unknown here, so report a synthetic marker for logs/tests.
Te6edf3disabledTff7b72.Td2a8ffappendTb4b4b4(Ta5d6ff"Ta5d6ff__i2p__Ta5d6ff"Tb4b4b4)
Tff7b72return Te6edf3disabled

Tff7b72if Te6edf3attempt Tff7b72== T79c0ff1Tb4b4b4:
Tff7b72if Te6edf3disable_rnode_interfaces_in_configTb4b4b4(
Te6edf3config_pathTb4b4b4,
Te6edf3is_androidTff7b72=Te6edf3_is_chaquopy_androidTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3disabledTff7b72.Td2a8ffappendTb4b4b4(Ta5d6ff"Ta5d6ff__rnode__Ta5d6ff"Tb4b4b4)
Te6edf3more Tff7b72= Te6edf3disable_interfaces_by_typeTb4b4b4(
Te6edf3config_pathTb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6ffSerialInterfaceTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffKISSInterfaceTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffAX25KISSInterfaceTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffPipeInterfaceTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3disabledTff7b72.Td2a8ffextendTb4b4b4(Te6edf3moreTb4b4b4)
Tff7b72return Te6edf3disabled

Tff7b72if Te6edf3attempt Tff7b72== T79c0ff2Tb4b4b4:
Te6edf3more Tff7b72= Te6edf3disable_interfaces_by_typeTb4b4b4(Te6edf3config_pathTb4b4b4, Tb4b4b4(Ta5d6ff"Ta5d6ffAutoInterfaceTa5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4)
Te6edf3disabledTff7b72.Td2a8ffextendTb4b4b4(Te6edf3moreTb4b4b4)
Tff7b72return Te6edf3disabled

T8b949e# Final attempts: peel off one high-risk enabled interface at a time.
Tff7b72for Te6edf3iface_type Tff7b72in Te6edf3_HIGH_RISK_TYPESTb4b4b4:
Te6edf3more Tff7b72= Te6edf3disable_interfaces_by_typeTb4b4b4(Te6edf3config_pathTb4b4b4, Tb4b4b4(Te6edf3iface_typeTb4b4b4,Tb4b4b4)Tb4b4b4, Te6edf3limitTff7b72=T79c0ff1Tb4b4b4)
Tff7b72if Te6edf3moreTb4b4b4:
Te6edf3disabledTff7b72.Td2a8ffextendTb4b4b4(Te6edf3moreTb4b4b4)
Tff7b72break
Tff7b72return Te6edf3disabled


Tff7b72def Td2a8ffcreate_reticulum_with_recoveryTb4b4b4(
Te6edf3config_dirTb4b4b4: Tffa657strTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3constructTb4b4b4: Te6edf3CallableTb4b4b4[Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3AnyTb4b4b4]Tb4b4b4,
Te6edf3max_attemptsTb4b4b4: Tffa657int Tff7b72= T79c0ff5Tb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Te6edf3AnyTb4b4b4:
T8b949e"""Construct RNS, progressively disabling bad interfaces on failure."""
Te6edf3install_rns_panic_containmentTb4b4b4(Tb4b4b4)
Te6edf3config_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3config_dirTb4b4b4, Ta5d6ff"Ta5d6ffconfigTa5d6ff"Tb4b4b4)
Te6edf3ensure_panic_on_interface_error_disabledTb4b4b4(Te6edf3config_pathTb4b4b4)

Te6edf3last_excTb4b4b4: Tf85149Exception Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72for Te6edf3attempt Tff7b72in Tffa657rangeTb4b4b4(Te6edf3max_attemptsTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72return Te6edf3constructTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3last_exc Tff7b72= Te6edf3exc
Te6edf3disabled Tff7b72= Te6edf3apply_startup_recovery_stepTb4b4b4(
Te6edf3config_pathTb4b4b4,
Te6edf3excTb4b4b4,
Te6edf3attemptTff7b72=Te6edf3attemptTb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3disabledTb4b4b4:
Tff7b72break
Tffa657printTb4b4b4(
Ta5d6ff"Ta5d6ffReticulum init failed; disabled Ta5d6ff"
Ta5d6fffTa5d6ff"Tffd700{Ta5d6ff'Ta5d6ff, Ta5d6ff'Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3disabledTb4b4b4)Tffd700}Ta5d6ff and retrying Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff(attempt Tffd700{Te6edf3attempt Tff7b72+ T79c0ff1Tffd700}Ta5d6ff/Tffd700{Te6edf3max_attemptsTffd700}Ta5d6ff). Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffError: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4,
Te6edf3flushTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)
Tff7b72assert Te6edf3last_exc Tff7b72is Tff7b72not Tff7b72None
Tff7b72raise Te6edf3last_exc


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────